//============================================================================
// Name        : ryan-prices.cpp
// Author      : Alexander Rogin
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <string>
#include <vector>

#include "FlightDatabase.h"
#include "Downloader.h"
#include "Configurator.h"

#include "Poco/Timestamp.h"
#include "Poco/String.h"
#include "Poco/StringTokenizer.h"
#include "Poco/NumberParser.h"
#include <ctime>

#define FROM_PARAM		"from"
#define TO_PARAM		"to"
#define MONTH_PARAM		"month"
#define UPDATE_PARAM	"update-data"
#define CHEAP_PARAM		"get-cheapest"

std::map<std::string, std::string> airports;
std::vector<std::string> flights;

enum CMD
{
		UPDATE_WITH_WEB	= 0,
		FIND_CHEAPEST 	= 1,

		INVALID_CMD = -1
};

void composeFlights(const std::string& from, const std::string& to,
		std::vector<std::string>& requestFlights)
{
	if (from.size() && to.size())
	{
		requestFlights.push_back(airports[from] + "-to-" + airports[to]);
		return;
	}
	else if (from.size())
	{
		std::size_t pos;
		for (std::string flight : flights)
		{
			pos = flight.find(airports[from]);
			if (pos != std::string::npos && pos == 0)
			{
				requestFlights.push_back(flight);
			}
		}
	}
	else if (to.size())
	{
		std::size_t pos;
		for (std::string flight : flights)
		{
			pos = flight.find(airports[to]);
			if (pos != std::string::npos && pos != 0)
			{
				requestFlights.push_back(flight);
			}
		}
	}
	else
	{
		requestFlights = flights;
	}
}

void showHelp()
{
	std::cout << "Usage: " << std::endl;
	std::cout << "./ryan-prices update-data|get-cheapest from=... to=... month=..." << std::endl;
}

int main(int argc, const char *argv[]) {
	Configurator::configure(airports, flights);

	std::string proxyAddr;
	int proxyPort;
	if (Configurator::getProxyParams(proxyAddr, proxyPort))
	{
		Downloader::setProxyParams(proxyAddr, proxyPort);
	}

	CMD cmd = INVALID_CMD;

	std::string from = "";
	std::string to = "";
	int month = 0;

	for (int i = 1; i < argc; ++i)
	{
		Poco::StringTokenizer t(argv[i], "=", Poco::StringTokenizer::TOK_IGNORE_EMPTY);
		if (!t[0].compare(FROM_PARAM))
		{
			from = Poco::toUpper(t[1]);
		}
		else if (!t[0].compare(TO_PARAM))
		{
			to = Poco::toUpper(t[1]);
		}
		else if (!t[0].compare(MONTH_PARAM))
		{
			month = Poco::NumberParser::parse(t[1]);
		}
		else if (!t[0].compare(UPDATE_PARAM))
		{
			if (cmd == INVALID_CMD)
			{
				cmd = UPDATE_WITH_WEB;
			}
			else
			{
				std::cout << "Parameter conflict: " << t[0] << " ignored" << std::endl;
			}
		}
		else if (!t[0].compare(CHEAP_PARAM))
		{
			if (cmd == INVALID_CMD)
			{
				cmd = FIND_CHEAPEST;
			}
			else
			{
				std::cout << "Parameter conflict: " << t[0] << " ignored" << std::endl;
			}
		}
	}
	if (cmd == INVALID_CMD)
	{
		showHelp();
		exit(EXIT_FAILURE);
	}

	FlightDatabase fd = FlightDatabase::getInstance();
	try
	{
		fd.loadFromFS();
	}
	catch (Poco::FileNotFoundException& e)
	{
		std::cout << "File with saved flights not found" << std::endl;
	}
	std::vector<std::string> requestFlights;
	composeFlights(from, to, requestFlights);

	switch (cmd)
	{
	case UPDATE_WITH_WEB:
	{
		std::cout << "Update has started, wait..." << std::endl;
		Poco::Timestamp now;
		for (std::string& flight : requestFlights)
		{
//			std::cout << "Flight " << flight << std::endl;
			fd.findFlights(flight, month);
		}
		Poco::Timestamp::TimeDiff dif = now.elapsed() / 1000000;
		unsigned int hours = dif / (60 * 60);
		dif %= (60 * 60);
		unsigned int mins = dif / 60;
		unsigned int secs = dif % 60;
		std::cout << "Took " << hours << " hours, " << mins << " minutes, " << secs << " seconds" << std::endl;
	}
	break;

	case FIND_CHEAPEST:
		std::cout << "Searching the cheapest..." << std::endl;
		if (to.size() || from.size())
		{
			for (std::string& flight : requestFlights)
			{
				fd.findCheapest(flight, month);
			}
		}
		else
		{
			fd.findCheapest(month);
		}

	break;

	default:
		std::cout << "Unknown command " << cmd << std::endl;
	}

	fd.saveData();

	return 0;
}

